package org.example.utils.map;

import com.google.common.collect.Lists;
import org.junit.jupiter.api.Test;
import org.springframework.util.LinkedCaseInsensitiveMap;

import java.util.*;
import java.util.stream.Collectors;

/**
 * Map API 测试
 *
 * @author wangMaoXiong
 * @version 1.0
 * @date 2022/3/4 10:05
 */
public class MapTest2 {

    /**
     * default V getOrDefault(Object key, V defaultValue)：返回指定键所映射的值，如果没有这个 key，则返回默认值 defaultValue
     */
    @Test
    public void testGetOrDefault() {
        Map<String, Object> dataMap = new HashMap<>();
        dataMap.put("id", "");
        dataMap.put("name", "华南");
        dataMap.put("age", null);

        // 华南
        System.out.println(dataMap.getOrDefault("name", ""));
        // 输出空
        System.out.println(dataMap.getOrDefault("id", "xx"));
        // null
        System.out.println(dataMap.getOrDefault("age", "yy"));
        // 500
        System.out.println(dataMap.getOrDefault("code", "500"));
    }

    /**
     * default V putIfAbsent(K key, V value)：如果指定的 key 不存在，或值 null，则继续设置，否则不设置。
     * key 不存在，或值 null 时，返回 null，否则返回当前值。
     */
    @Test
    public void testPutIfAbsent() {
        Map<String, Object> dataMap = new HashMap<>();
        dataMap.put("id", "");
        dataMap.put("name", "华南");
        dataMap.put("age", null);

        Object ifAbsentId = dataMap.putIfAbsent("id", "1001");
        Object ifAbsentName = dataMap.putIfAbsent("name", "华安");
        Object ifAbsentAge = dataMap.putIfAbsent("age", "32");
        Object ifAbsentSex = dataMap.putIfAbsent("sex", "男");

        // ,华南,null,null
        System.out.println(ifAbsentId + "," + ifAbsentName + "," + ifAbsentAge + "," + ifAbsentSex);

        // {sex=男, name=华南, id=, age=32}
        System.out.println(dataMap);
    }


    /**
     * V compute(K key, BiFunction<? super K, ? super V, ? extends V> remappingFunction)：计算，主要有3步操作
     * 获取到key对应的oldValue，可能为null
     * 经过 remappingFunction(key, oldValue)计算获取 newValue
     * 如果新值不为null，则 put(key, newValue)；如果新值为null，则移除key
     */
    @Test
    public void testComputer() {
        // 演示统计List中元素出现的次数
        Map<String, Integer> cntMap = new HashMap<>(8);
        List<String> list = Arrays.asList("apple", "orange", "banana", "orange");
        for (String item : list) {
            cntMap.compute(item, (key, oldValue) -> oldValue == null ? 1 : oldValue + 1);
        }
        // {banana=1, orange=2, apple=1}
        System.out.println(cntMap);
    }

    /**
     * V computeIfAbsent(K key, Function<? super K, ? extends V> mappingFunction)
     * 1、key不存在，或者对应的value值为 null 时，执行 mappingFunction 函数，然后赋值给map。
     * 2、mappingFunction 传入的是 map 的 key，返回的它的新值.
     */
    @Test
    public void testComputeIfAbsent() {
        Map<String, Object> dataMap = new LinkedHashMap<>();
        dataMap.put("id", "");
        dataMap.put("name", "华南");
        dataMap.put("age", null);

        dataMap.computeIfAbsent("id", key -> "9527");
        dataMap.computeIfAbsent("name", key -> "华安");
        dataMap.computeIfAbsent("age", key -> "31");
        dataMap.computeIfAbsent("sex", key -> key + "#1");

        System.out.println(dataMap);// {id=, name=华南, age=31, sex=sex#1}

        Map<String, List<String>> dataMap2 = new HashMap<>();
        dataMap2.put("color", Lists.newArrayList("red", "green", "blue"));

        dataMap2.computeIfAbsent("size", key -> Arrays.asList("1", "2", "3", "4"));
        dataMap2.computeIfAbsent("color", key -> Arrays.asList("1", "2", "3", "4")).add("yellow");

        System.out.println(dataMap2);// {size=[1, 2, 3, 4], color=[red, green, blue, yellow]}
    }

    /**
     * V computeIfPresent(K key, BiFunction<? super K, ? super V, ? extends V> remappingFunction)
     * 1、key存在且值不为null时，才去执行 remappingFunction 函数，然后用新值覆盖旧值。否则当key不存在，或者值为null时，不会有任何效果.
     * 2、remappingFunction 函数第一个参数是key的名称，第二个参数旧value，返回新的value。
     */
    @Test
    public void testComputeIfPresent() {
        Map<String, Object> dataMap = new LinkedHashMap<>();
        dataMap.put("id", "");
        dataMap.put("name", "华南");
        dataMap.put("age", null);

        dataMap.computeIfPresent("id", (key, oldValue) -> oldValue + "_");
        dataMap.computeIfPresent("name", (key, oldValue) -> oldValue + "_");
        dataMap.computeIfPresent("age", (key, oldValue) -> "31");
        dataMap.computeIfPresent("sex", (key, oldValue) -> key + "#1");

        System.out.println(dataMap);// {id=_, name=华南_, age=null}

        Map<String, List<String>> dataMap2 = new HashMap<>();
        dataMap2.put("color", Lists.newArrayList("red", "green", "blue"));

        dataMap2.computeIfPresent("size", (key, oldValue) -> Arrays.asList("1", "2", "3", "4"));
        dataMap2.computeIfPresent("color", (key, oldValue) -> oldValue.stream().map(String::toUpperCase).collect(Collectors.toList()));

        System.out.println(dataMap2);// {color=[RED, GREEN, BLUE]}
    }

    /**
     * {@link org.springframework.util.LinkedCaseInsensitiveMap} 以不区分大小写的方式存储字符串的 key 。
     * key 不支持存储 null.
     */
    @Test
    public void testLinkedCaseInsensitiveMap() {
        Map<String, Object> caseInsensitiveMap = new LinkedCaseInsensitiveMap<>();
        caseInsensitiveMap.put("code", 200);
        caseInsensitiveMap.put("msg", "key 不区分大小写");

        // {code=200, msg=key 不区分大小写}
        System.out.println(caseInsensitiveMap);
        // 200
        System.out.println(caseInsensitiveMap.get("CODE"));
        caseInsensitiveMap.put("CODE", 500);
        // 500
        System.out.println(caseInsensitiveMap.get("code"));
    }

    /**
     * TreeMap 中的元素按自然顺序自动排序.
     */
    @Test
    public void testTreeMap() {
        Map<String, Object> treeMap = new TreeMap<>();
        treeMap.put("001003", "正厅级");
        treeMap.put("001002", "副国级");
        treeMap.put("001004", "副厅级");
        treeMap.put("001001", "正国级");

        // {001001=正国级, 001002=副国级, 001003=正厅级, 001004=副厅级}
        System.out.println(treeMap);
    }

    /**
     * V merge(K key, V value, BiFunction<? super V, ? super V, ? extends V> remappingFunction) 合并entry
     * * 如果key存在，且旧值不为null，则将value按照function做1次计算后，更新到Map中
     * * 如果key不存在，将key-value直接放入Map中
     * * 如果新value值为null，则会移除key
     */
    @Test
    public void testMerge() {
        // 演示统计List中元素出现的次数
        Map<String, Integer> cntMap1 = new HashMap<>(8);
        Map<String, Integer> cntMap2 = new HashMap<>(8);
        List<String> list = Arrays.asList("apple", "orange", "banana", "orange");
        for (String item : list) {
            // 老写法
            if (cntMap1.containsKey(item)) {
                cntMap1.put(item, cntMap1.get(item) + 1);
            } else {
                cntMap1.put(item, 1);
            }
            // 新写法
            cntMap2.merge(item, 1, Integer::sum);
        }
        // {orange=2, banana=1, apple=1}
        System.out.println(cntMap1);

        // {banana=1, orange=2, apple=1}
        System.out.println(cntMap2);
    }

    /**
     * V replace(K key, V value) ：元素值替换，只有当key存在时才执行替换，否则不替换。
     * boolean replace(K key, V oldValue, V newValue)：元素值替换，只有当key存在且旧值等于oldValue时才执行替换，否则不替换。
     */
    @Test
    public void testReplace() {
        Map<String, Object> dataMap = new HashMap<>();
        dataMap.put("id", "");
        dataMap.put("name", "华南");
        dataMap.put("age", null);

        dataMap.replace("id", "1001");
        dataMap.replace("name", "华北");
        dataMap.replace("age", 55);
        dataMap.replace("sal", 8885);
        // {name=华北, id=1001, age=55}
        System.out.println(dataMap);
    }

}
